import io
import logging
import random  # 添加这个导入

from django.contrib.auth.models import User
from django.http import HttpResponse
from django.shortcuts import render
from django.views import View
from django_redis import get_redis_connection
from fdfs_client.client import get_tracker_conf, Fdfs_client
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.status import HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR
from rest_framework.viewsets import ModelViewSet, GenericViewSet, ReadOnlyModelViewSet
from rest_framework_simplejwt.views import TokenObtainPairView
# 添加这一行导入
from rest_framework_extensions.cache.mixins import CacheResponseMixin

from config.dbs.reidsConfig import KEY_TEMPLATE, EXPIRE_TIME
from .models import *
from .serializers import *
from utils.verifyUtil import ImageVerify, generate_sms_code  # 修改导入，添加 generate_sms_code

from celery_tasks.sms.tasks import send_order_sms_task
import random
import string
from django_redis import get_redis_connection
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import status

"""
图片验证码：
正确答案：字母 数字
干扰信息：干扰线 干扰点
生成一张图片
PIL库 ：python的第三方图像处理库
pillow
"""


class ImageVerifyView(View):
    def get(self, request, func, uuid):
        """
        :param request:  请求对象
        :return:  验证码图片
        """
        imageVerify = ImageVerify()
        # img保存的图片数据
        img, code = imageVerify.verify_code()
        # 现在我们不需要把图片保存到服务器上面了
        # 只需要将图片数据返回给到客户端 不需要做持久化的操作
        # 图片是字节流 文件流:字符流 字节流
        # 启动应用程序时 会划一部分的内存用于保存该文件
        # 但是这个文件并不会实际存在在你的电脑当中 当程序结束，内存也会被释放，文件也会被删除，只会临时存在一段时间
        # 生成一个临时的字节流文件对象
        img_bytes = io.BytesIO()
        # 把图片数据保存到该字节流文件中
        img.save(img_bytes, format='PNG')
        # 获取图片数据重新赋值 文件数据
        img_bytes = img_bytes.getvalue()

        # 把uuid为键 验证码答案为值保存到redis数据库里面
        cache = get_redis_connection(alias='verify_codes')
        # KEY_TEMPLATE % (func, uuid) 为键 func 请求是登录还是注册 uuid 用户身份识别信息
        # set在数据库里面添加一个键值对数据  code 为值
        # EXPIRE_TIME过期时间
        cache.set(KEY_TEMPLATE % (func, uuid), code, EXPIRE_TIME)
        return HttpResponse(img_bytes, content_type='image/png')


# 导入日志器
logger = logging.getLogger(__name__)
# 获取tracker服务的地址
tracker_path = get_tracker_conf('utils/fastdfs/client.conf')
# 链接fastdfs的服务
client = Fdfs_client(tracker_path)


# 添加生成短信验证码的工具函数
def generate_sms_code(length=6):
    """
    生成短信验证码
    :param length: 验证码长度，默认6位
    :return: 随机数字组成的字符串
    """
    return ''.join(random.choices(string.digits, k=length))


class UserViewSet(GenericViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    # 针对方法的校验 接口级别的权限指定
    def get_permissions(self):
        # 如果当前的行为是调用now方法，就添加一个登录校验
        if self.action in ['now', "info"]:
            permission_classes = [IsAuthenticated]  # IsAuthenticated登录权限类
        else:
            # 调用其他的方法就不设置权限
            permission_classes = []
        # 返回值也是一个列表 并且列表里面的元素需要是一个权限对象

        return [permission() for permission in permission_classes]

    # 接口级别的序列化器指定
    def get_serializer_class(self):
        if self.action in ["info"]:
            return UserDetailSerializer
        elif self.action in ["password"]:
            return UpdatePasswordSerializer
        else:
            return self.serializer_class

    # 创建的方法有些不同 所以需要重新定义创建的方法
    def create(self, request, *args, **kwargs):
        # 通过序列化器进行反序列化的校验
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 获取到用户填写的信息
        username = request.data.get("username")
        password = request.data.get("password")
        email = request.data.get("email")

        # 保存用户信息 创建一个模型对象
        user = User(username=username, email=email)
        user.set_password(password)
        user.save()
        # 利用序列化器进行序列化 返回创建的用户信息
        return Response(self.get_serializer(user).data)

    @action(methods=['get'], detail=False)
    def now(self, request):
        # 获取用户信息
        data = request.user
        print(data)

        # 把用户信息做反序列化的操作
        serializer = self.get_serializer(data)
        return Response(serializer.data)

    @action(methods=["put"], detail=False)
    def info(self, request):
        print(request.data)
        # 得到当前登录的用户信息
        user = request.user
        # 限制修改的用户信息 只能为当前用户的
        # 允许被修改
        request.POST._mutable = True
        # 限制用户id为当前登录的用户id
        request.data["user"] = user.id
        file = request.FILES.get("file")
        # 记录是否需要删除旧头像图片
        need_delete_old_avatar = False
        # 判断是否有文件数据
        if file:
            # 判断是否是图片类型
            if file.content_type not in ("image/jpeg", "image/png"):
                return Response(status=HTTP_400_BAD_REQUEST)
            # 判断文件是否有后缀名 如果文件没有后缀名
            try:
                images_ext_name = file.name.split(".")[-1]
            except Exception as e:
                # 导入日志器，把信息记录到日志文件中
                logger.info("图片拓展名异常%s" % e)
                # 默认修改为png
                images_ext_name = "png"
            # 上传图片数据
            # django通过request。file得到的是图片数据 不是图片文件
            try:
                upload_res = client.upload_by_buffer(file.read(), file_ext_name=images_ext_name)
            except Exception as e:
                logger.error("图片上传出现异常：%s" % e)
                return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)
            else:
                # 请求成功了 判断是否上传成功
                if upload_res.get("Status") != "Upload successed.":
                    logger.warning("图片上传失败")
                    return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)

                # 得到图片保存的路由地址信息，写入到数据库中
                image_name = upload_res.get("Remote file_id").decode()  # 解码得到图片字符串地址
                request.data["avatar"] = image_name
        # 判断该用户是否有详情数据
        '''
        内置函数 类属性的操作
        hasattr 判断对象是否有该属性
        setattr 设置对象的属性和属性值
        getattr 获取对象的属性值
        delattr 删除对象的属性
        '''
        if hasattr(user, "userdetail"):
            # 如果有就修改
            if request.data.get('email'):
                user.email = request.data["email"]
                user.userdetail.gender = request.data["sex"]
                user.save()
            # 如果有之前的头像图片就删除
            if getattr(user.userdetail, "avatar"):
                need_delete_old_avatar = True
            user_detail_serializer = self.get_serializer(user.userdetail, data=request.data)

        else:
            # 没有就创建
            # request请求里面传过来的数据 测试是可以看到用户的名字 可以传其他用户的名字
            # 修改其他用户的信息
            user_detail_serializer = self.get_serializer(data=request.data)
        user_detail_serializer.is_valid(raise_exception=True)
        user_detail_serializer.save()
        return Response(user_detail_serializer.data)

    @action(methods=["put"], detail=False)
    def password(self, request):
        user = request.user
        serializers = self.get_serializer(data=request.data)
        serializers.is_valid(raise_exception=True)
        password = request.data["password"]
        new_password = request.data["new_password"]
        # 校验
        if user.check_password(password):
            # 加密
            user.set_password(new_password)
            user.save()
            return Response({"msg": "修改成功"})
        else:
            return Response(status=HTTP_400_BAD_REQUEST)

    # 在用户相关视图中
    # 发送短信验证码
    @action(methods=["post"], detail=False)
    def send_sms_code(self, request):
        """
        发送短信验证码
        """
        mobile = request.data.get('mobile')

        # 验证手机号格式
        if not mobile or not mobile.isdigit() or len(mobile) != 11:
            return Response({'message': '手机号格式不正确'}, status=status.HTTP_400_BAD_REQUEST)

        # 生成6位随机数字验证码
        sms_code = generate_sms_code(6)

        # 将验证码保存到Redis中，过期时间5分钟
        cache = get_redis_connection(alias='verify_codes')
        cache.set(f'sms_{mobile}', sms_code, 300)  # 300秒 = 5分钟

        # 异步发送短信
        from celery_tasks.sms.tasks import send_sms_task
        send_sms_task.delay(mobile, sms_code)

        return Response({'message': '短信验证码已发送'})


class MyTokenObtainPairView(TokenObtainPairView):
    serializer_class = MyTokenObtainPairSerializer


class AreaViewSet(CacheResponseMixin, ReadOnlyModelViewSet):
    queryset = Area.objects.all()
    serializer_class = AreaSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):  # 重写 get_queryset方法
        if self.action == "list":
            return Area.objects.filter(parent=None)
        else:
            return self.queryset

    def get_serializer_class(self):  # 重写 get_serializer_class方法
        if self.action == "retrieve":
            return ParentAreaSerializer
        else:
            return self.serializer_class


# 收货地址查询集
class AddressViewSet(ModelViewSet):
    queryset = Address.objects.all()
    serializer_class = AddressSerializer
    permission_classes = [IsAuthenticated]

    # 获取当前登录用户的收货地址
    def get_queryset(self):
        # 通过管理器获取当前用户的所有收货地址
        return self.request.user.address_set.all()

    # 重写create方法
    def create(self, request, *args, **kwargs):
        max_count = 5
        if self.get_queryset().count() >= max_count:
            return Response({"message": "收货地址数量已经达到上限"}, status=HTTP_400_BAD_REQUEST)
        request.POST._mutable = True
        request.data["user"] = str(request.user.id)
        return ModelViewSet.create(self, request, *args, **kwargs)
